package cn.qzzg.controller;


import cn.qzzg.common.ResultBean;
import cn.qzzg.config.WxConfig;
import cn.qzzg.dto.WxDto;
import cn.qzzg.enums.CodeEnum;
import cn.qzzg.pojo.User;
import cn.qzzg.service.UserService;
import cn.qzzg.util.HttpClientUtil;
import cn.qzzg.util.JJWTTokenUtil;
import cn.qzzg.util.RedisUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;


@RestController
@RequestMapping("/wx")
public class WxController {
    @Resource
    WxConfig wxConfig;
    @Resource
    RedisUtil redisUtil;
    @Resource
    UserService userService;

    @GetMapping("/authorize")
    public void authorize(HttpServletResponse response, WxDto wxDto) throws IOException {
        String url = wxConfig.getAuthorizeInterface()
                .replace("APPID", wxConfig.getAppId())
                .replace("REDIRECTURI", URLEncoder.encode(wxDto.getBackendAddress() + "/wx/callBack", "UTF-8"))
                .replace("FRONTENDADDRESS", wxDto.getFrontendAddress())
                .replace("TYPE", wxDto.getType());
        response.sendRedirect(url);
    }

    @GetMapping("/callBack")
    public void callBack(HttpServletRequest request, HttpServletResponse response, WxDto wxDto) throws IOException {
        String frontendAddress = wxDto.getFrontendAddress().split("PARAM")[0];
        String type = wxDto.getFrontendAddress().split("PARAM")[1];
        String openId;
        String code = request.getParameter("code");
        Map<String, String> params = new HashMap<>();
        params.put("secret", wxConfig.getAppSecret());
        params.put("appid", wxConfig.getAppId());
        params.put("grant_type", "authorization_code");
        params.put("code", code);
        String info = HttpClientUtil.doGet(wxConfig.getOpenIdInterface(), params);
        if (info != null) {
            JSONObject object = (JSONObject) JSON.parse(info);
            openId = object.getString("openid");
            String url = frontendAddress;
            User user = userService.findByOpenId(openId);
            if (type.equals("4") && user != null && user.getRoleId() != 0 && user.getRoleId() != 1) {
                String token = JJWTTokenUtil.createToken(user.getUserId());
                redisUtil.setHash("user_token", user.getUserId(), token, 10L, TimeUnit.MINUTES);
                url += "/home?Authorization=" + token;
            } else {
                url += "/register?type=" + type;
                if (user == null)
                    url += "&openId=" + openId;
            }
            response.sendRedirect(url);
        }
    }

    /**
     * 获取登录二维码
     */
    @GetMapping("/subscribeQrCode")
    private ResultBean<?> subscribeQrCode() throws IOException {
        // String accessToken = getAccessToken();
        String getQrCodeUrl = wxConfig.getQrCodeInterface()
                .replace("ACCESSTOKEN", wxConfig.getAccessToken());
        // 这里生成一个带参数的二维码，参数是sceneStr
        String sceneStr = UUID.randomUUID().toString();
        JSONObject json = new JSONObject();
        json.put("expire_seconds", 604800);
        json.put("action_name", "QR_STR_SCENE");
        JSONObject actionInfo = new JSONObject();
        JSONObject scene = new JSONObject();
        scene.put("scene_str", sceneStr);
        actionInfo.put("scene", scene);
        json.put("action_info", actionInfo);
        String result = HttpClientUtil.doPostJson(getQrCodeUrl, json.toString());
        JSONObject jsonObject = JSONObject.parseObject(result);
        jsonObject.put("scene_str", sceneStr);
        jsonObject.put("qr_code_url", wxConfig.getShowQrCodeInterface().replace("TICKET", jsonObject.get("ticket").toString()));
        return ResultBean.success(jsonObject);
    }

    /**
     * 验证签名
     */
    @RequestMapping("/checkSign")
    public String checkSign(HttpServletRequest request) throws Exception {
        // 获取微信请求参数
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        // 参数排序。 token 就要换成自己实际写的 token
        String[] params = new String[]{timestamp, nonce, wxConfig.getToken()};
        Arrays.sort(params);
        String paramStr = params[0] + params[1] + params[2];
        // 加密
        // 获取 sha-1 算法封装类
        MessageDigest Sha1Encryption = MessageDigest.getInstance("SHA-1");
        // 进行加密并转换为String
        byte[] digestResult = Sha1Encryption.digest(paramStr.getBytes(StandardCharsets.UTF_8));
        byte[] hex = "0123456789ABCDEF".getBytes();
        byte[] buff = new byte[2 * digestResult.length];
        for (int i = 0; i < digestResult.length; i++) {
            buff[2 * i] = hex[(digestResult[i] >> 4) & 0x0f];
            buff[2 * i + 1] = hex[digestResult[i] & 0x0f];
        }
        String mySignature = new String(buff).toLowerCase(Locale.ROOT);

        if (mySignature.equals(signature) && echostr != null) return echostr;
        else return null;
    }

    @GetMapping("/updateMenu")
    public ResultBean<?> updateMenu(WxDto wxDto) throws IOException {
        String accessToken = wxConfig.getAccessToken();
        String url = wxConfig.getMenuUrlInterface()
                .replace("FRONTENDADDRESS", wxDto.getFrontendAddress())
                .replace("BACKENDADDRESS", wxDto.getBackendAddress());

        JSONObject menu = new JSONObject();
        JSONArray buttonArray = new JSONArray();
        JSONObject button1 = new JSONObject();
        button1.put("name", "注册");
        JSONArray subButtonArray = new JSONArray();
        JSONObject subButton1 = new JSONObject();
        subButton1.put("type", "view");
        subButton1.put("name", "管理注册");
        subButton1.put("url", url + "&type=3");
        subButtonArray.add(subButton1);
        JSONObject subButton2 = new JSONObject();
        subButton2.put("type", "view");
        subButton2.put("name", "社区注册");
        subButton2.put("url", url + "&type=2");
        subButtonArray.add(subButton2);
        JSONObject subButton3 = new JSONObject();
        subButton3.put("type", "view");
        subButton3.put("name", "个人注册");
        subButton3.put("url", url + "&type=1");
        subButtonArray.add(subButton3);
        button1.put("sub_button", subButtonArray);
        buttonArray.add(button1);
        JSONObject button2 = new JSONObject();
        button2.put("type", "view");
        button2.put("name", "核酸接收");
        button2.put("url", url + "&type=4");
        buttonArray.add(button2);
        menu.put("button", buttonArray);


        String deleteUrl = wxConfig.getDeleteMenuInterface().replace("ACCESSTOKEN", accessToken);

        HttpGet httpGet = new HttpGet(deleteUrl);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = httpClient.execute(httpGet);
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            String createUrl = wxConfig.getCreateMenuInterface().replace("ACCESSTOKEN", accessToken);
            HttpPost createHttpPost = new HttpPost(createUrl);
            createHttpPost.setHeader("Content-Type", "application/json");
            createHttpPost.setEntity(new StringEntity(menu.toString(), "UTF-8"));
            response = httpClient.execute(createHttpPost);
            entity = response.getEntity();
            if (entity != null) {
                return ResultBean.success();
            }
        }
        return ResultBean.error(CodeEnum.SYSTEM_ERROR_B0001);
    }

    @GetMapping(value = "/sign")
    public ResultBean<?> sign(String url) throws NoSuchAlgorithmException {
        Map<String, Object> data = new HashMap<>();
        String nonce_str = UUID.randomUUID().toString();
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        String parameter = String.format("jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s", wxConfig.getTicket(), nonce_str, timestamp, url);

        MessageDigest instance = MessageDigest.getInstance("SHA-1");
        instance.reset();
        instance.update(parameter.getBytes(StandardCharsets.UTF_8));
        Formatter formatter = new Formatter();
        for (byte b : instance.digest())
            formatter.format("%02x", b);
        String signature = formatter.toString();
        formatter.close();

        data.put("url", url);
        data.put("nonceStr", nonce_str);
        data.put("timestamp", Integer.parseInt(timestamp));
        data.put("signature", signature);
        data.put("jsapi_ticket", wxConfig.getTicket());
        data.put("appId", wxConfig.getAppId());
        return ResultBean.success(data);
    }

    @GetMapping("/getAccessTokenAndTicket")
    public ResultBean<?> getAccessTokenAndTicket() throws IOException {
        String accessToken = getAccessToken();
        Map<String, String> map = new HashMap<>();
        map.put("accessToken", accessToken);
        map.put("ticket", getTicket(accessToken));
        return ResultBean.success(map);
    }

    public String getAccessToken() throws IOException {
        String getTokenUrl = wxConfig.getAccessTokenInterface()
                .replace("APPID", wxConfig.getAppId())
                .replace("APPSECRET", wxConfig.getAppSecret());
        return JSONObject.parseObject(HttpClientUtil.doGet(getTokenUrl)).getString("access_token");
    }

    public String getTicket() throws IOException {
        String getTicketUrl = wxConfig.getTicketInterface()
                .replace("ACCESSTOKEN", wxConfig.getTicket());
        return JSONObject.parseObject(HttpClientUtil.doGet(getTicketUrl)).getString("ticket");
    }

    public String getTicket(String accessToken) throws IOException {
        String getTicketUrl = wxConfig.getTicketInterface()
                .replace("ACCESSTOKEN", accessToken);
        return JSONObject.parseObject(HttpClientUtil.doGet(getTicketUrl)).getString("ticket");
    }
}
